home *** CD-ROM | disk | FTP | other *** search
/ Team Palmtops 7 / Palmtops_numero07.iso / WinCE / SDKWindowsCE / HandHeldPCPro30 / sdk.exe / Jupiter SDK / data1.cab / MFC / src / wcesock.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1999-02-19  |  14.8 KB  |  667 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #include "stdafx.h"
  12. #if !defined(_WIN32_WCE_NO_WINSOCK)
  13.  
  14. // WinCE: CCeSocket creates 1-2 worker threads, but they need to access
  15. // data structures that are set up by the main thread (AfxSocketInit()).
  16. #define _afxSockThreadState wce_GetSockThreadState()
  17.  
  18. AFX_MODULE_THREAD_STATE* wce_GetSockThreadState()
  19. {
  20.     static AFX_MODULE_THREAD_STATE* pMainThreadState = NULL;
  21.  
  22.     if(pMainThreadState == NULL)
  23.         pMainThreadState = AfxGetModuleThreadState();
  24.     return pMainThreadState;
  25. }
  26.  
  27. HWND AfxGetCeSocketWindow()
  28. {
  29.     HWND hWndSocket = wce_GetSockThreadState()->m_hSocketWindow;
  30.     ASSERT(hWndSocket != NULL);
  31.     return hWndSocket;
  32. }
  33.  
  34.  
  35. unsigned int  AFX_CDECL ListenThread( void* pvParams );
  36. unsigned int  AFX_CDECL DataThread( void* pvParams );
  37.  
  38. CWinThread* CCeSocket::m_pListenThread = 0;
  39. CWinThread* CCeSocket::m_pDataThread   = 0;
  40. int         CCeSocket::m_iSocketCount  = 0;                         
  41.  
  42. CPtrList    CeDataSockets;
  43.  
  44.  
  45. CCeSocket::CCeSocket( PURPOSE_E iPurpose )
  46. {
  47.     ASSERT((iPurpose==FOR_LISTENING) || (iPurpose==FOR_DATA));
  48.  
  49.     m_iPurpose       = iPurpose;
  50.     m_bConnectCalled = FALSE;
  51.     m_bIsConnected   = FALSE;
  52.     m_bQuit          = FALSE;
  53.  
  54.      // Initialize the fd_set's.
  55.      // NOTE: Because m_ReadFds and m_WriteFds are global, we really don't want
  56.      //       to reset them everytime that the constructor gets called.
  57.     FD_ZERO(&m_ReadFds);
  58.     FD_ZERO(&m_WriteFds);
  59.  
  60.     // If this is a data socket, then add it to the list.
  61.     if (m_iPurpose == FOR_DATA)
  62.         CeDataSockets.AddTail(this);
  63.  
  64.     // Increment socket counter.
  65.     m_iSocketCount++;
  66.  
  67.     return;
  68. }
  69.  
  70.  
  71.  
  72. void CCeSocket::BeginThread( PURPOSE_E iPurpose )
  73. {
  74.     // Start-up the listening or data thread.
  75.     switch (iPurpose)  {
  76.     case FOR_LISTENING:
  77.         // If we haven't already done so, startup the listening thread.
  78.         if (m_pListenThread == 0)
  79.         {
  80.             m_pListenThread = AfxBeginThread( ListenThread, (LPVOID)this, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED );
  81.             m_pListenThread->m_bAutoDelete = FALSE;
  82.             m_pListenThread->ResumeThread();
  83.         }
  84.         break;
  85.     case FOR_DATA:
  86.         // If we haven't already done so, startup the data thread.
  87.         if (m_pDataThread == 0)
  88.         {
  89.             m_pDataThread = AfxBeginThread( DataThread, (LPVOID)NULL, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED );
  90.             m_pDataThread->m_bAutoDelete = FALSE;
  91.             m_pDataThread->ResumeThread();
  92.         }
  93.         break;
  94.     default:
  95.         ASSERT(FALSE);
  96.     }
  97. }
  98.  
  99.  
  100.  
  101.  
  102. void CCeSocket::EndThreads()
  103. {
  104.     ASSERT(m_iSocketCount==0);
  105.  
  106.     // Conditionally, kill listening thread.
  107.     if (m_pListenThread)
  108.     {
  109.         delete m_pListenThread;
  110.         m_pListenThread = 0;
  111.     }
  112.  
  113.     // Conditionally, kill data thread.
  114.     if (m_pDataThread)
  115.     {
  116.         delete m_pDataThread;
  117.         m_pDataThread = 0;
  118.     }
  119. }
  120.  
  121.  
  122.  
  123.  
  124. CCeSocket::~CCeSocket() 
  125. {
  126.     m_bQuit = TRUE;
  127.     // If this is a data socket, then remove it from the list.
  128.     if (m_iPurpose == FOR_DATA)
  129.     {
  130.         POSITION pos,temp;
  131.         for (pos = CeDataSockets.GetHeadPosition(); pos != NULL; )
  132.         {
  133.             temp = pos;
  134.             CSocket* pSock = (CSocket*)CeDataSockets.GetNext(pos);
  135.             if (pSock == this)
  136.             {
  137.                 CeDataSockets.RemoveAt(temp);
  138.                 break;
  139.             }
  140.         }
  141.     }
  142.  
  143.     // Close the socket.
  144.     CSocket::Close();
  145.  
  146.     // Decrement socket counter and, conditionally, delete the listening 
  147.     // and data thread objects. 
  148.     m_iSocketCount--;
  149.     if (m_iSocketCount <= 0)
  150.     {
  151.         // Kill the threads.
  152.         m_iSocketCount = 0;
  153.         Sleep( 200 );
  154.     }
  155.  
  156.     return;
  157. }
  158.  
  159.  
  160.  
  161.  
  162. BOOL CCeSocket::Create( UINT nSocketPort )
  163. {
  164.     timeval tv = { 0 /*sec*/, 1000 /*usec*/ };
  165.  
  166.     // NOTE: This is where m_hSocket gets filled-in for listening sockets.
  167.     if (! CAsyncSocket::Create( nSocketPort ))
  168.     {
  169.         ASSERT(FALSE);
  170.         return (FALSE);
  171.     }
  172.     if (m_hSocket == INVALID_SOCKET)
  173.     {
  174.         ASSERT(FALSE);                      
  175.         return (FALSE);
  176.     }
  177.  
  178.     // Make sure that the handle is attached.
  179.     if (! LookupHandle( m_hSocket, FALSE ))
  180.     {
  181.         ASSERT(FALSE);
  182.         Attach( m_hSocket );
  183.     }
  184.  
  185.     FD_SET(m_hSocket, &m_ReadFds );
  186.     int iRetCode = select( 0, &m_ReadFds, NULL, NULL, &tv );
  187.     if (iRetCode == SOCKET_ERROR)
  188.     {
  189.         // It could be that one of the descriptor sets contains an entry
  190.         // that is no longer a socket (e.g. when a socket is closed).
  191.         // This is okay.  It occurs when a connection is closed at the
  192.         // other end.
  193.         int iErr = ::GetLastError();
  194.         if (iErr != WSAENOTSOCK)
  195.         {
  196.             ASSERT(FALSE);
  197.             return (FALSE);
  198.         }
  199.     }
  200.  
  201.     m_bConnectCalled = FALSE; // Wait until ConnectHelper() is called before
  202.                               // letting the thread call DoConnect()
  203.  
  204.     // Start-up the listening and data thread.
  205.     BeginThread( m_iPurpose );
  206.     if(m_iPurpose != FOR_DATA)
  207.         BeginThread( FOR_DATA );
  208.  
  209.     // If this is a FOR_DATA socket, then return now.
  210.     if (m_iPurpose == FOR_DATA)
  211.         return (TRUE);
  212.  
  213.     // Set the listening socket to non-blocking.
  214.     if (! SetNonblocking())
  215.     {
  216.         ASSERT(FALSE);
  217.     }
  218.  
  219.     return (TRUE);
  220. }
  221.  
  222.  
  223. BOOL CCeSocket::ConnectHelper(const SOCKADDR* lpSockAddr, int nSockAddrLen)
  224. {
  225.     m_bConnectCalled = FALSE;
  226.     BOOL bResult = CSocket::ConnectHelper(lpSockAddr,nSockAddrLen);
  227.     if (bResult) m_bConnectCalled = TRUE;
  228.     return bResult;
  229. }
  230.  
  231.  
  232.  
  233.  
  234. BOOL CCeSocket::IsAlive()
  235. {
  236.     int  iResult;                                              
  237.     int     iLen = sizeof(int);                       
  238.  
  239.     if (getsockopt( m_hSocket, SOL_SOCKET, SO_TYPE, (char*)&iResult, &iLen ) == SOCKET_ERROR)
  240.         return (FALSE);
  241.  
  242.     return (TRUE);
  243. }
  244.  
  245.  
  246.  
  247.  
  248. BOOL CCeSocket::IsListening()
  249. {
  250.     int  iResult;
  251.     int     iLen = sizeof(int);
  252.  
  253.     if (getsockopt( m_hSocket, SOL_SOCKET, SO_ACCEPTCONN, (char*)&iResult, &iLen ) == SOCKET_ERROR)
  254.     {
  255.         int iErr = WSAGetLastError();
  256.         if (iErr != WSAENOTSOCK)
  257.             ASSERT(FALSE);
  258.         return (FALSE);
  259.     }
  260.  
  261.     if (iResult)
  262.         return (TRUE);
  263.  
  264.     return (FALSE);
  265. }
  266.  
  267.  
  268.  
  269. BOOL CCeSocket::IsReadReady()
  270. {
  271.     unsigned long ulResult;
  272.  
  273.     if (ioctlsocket( m_hSocket, FIONREAD, &ulResult ) == SOCKET_ERROR)
  274.     {
  275.         int iErr = WSAGetLastError();
  276.         if (iErr != WSAENOTSOCK)
  277.             ASSERT(FALSE);
  278.         return (FALSE);
  279.     }
  280.  
  281.     if (ulResult > 0)
  282.         return (TRUE);
  283.  
  284.     return (FALSE);
  285. }
  286.  
  287.  
  288.  
  289.  
  290. BOOL CCeSocket::SetForRead()
  291. {
  292.     FD_CLR( m_hSocket, &m_ReadFds );
  293.     FD_SET( m_hSocket, &m_ReadFds );
  294.  
  295.     timeval tv = { 0 /*sec*/, 1000 /*usec*/ };
  296.     int iRetCode = select( 0, &m_ReadFds, NULL, NULL, &tv );
  297.     if (iRetCode == SOCKET_ERROR)
  298.     {
  299.         // It could be that one of the descriptor sets contains an entry
  300.         // that is no longer a socket (e.g. when a socket is closed).
  301.         // This is okay.  It occurs when a connection is closed at the
  302.         // other end.
  303.         int iErr = WSAGetLastError();
  304.         if (iErr != WSAENOTSOCK)
  305.         {
  306.             ASSERT(FALSE);
  307.             return (FALSE);
  308.         }
  309.     }
  310.  
  311.     return (TRUE);
  312. }
  313.  
  314.  
  315.  
  316.  
  317. BOOL CCeSocket::SetForWrite()
  318. {
  319.     FD_CLR( m_hSocket, &m_WriteFds );
  320.     FD_SET( m_hSocket, &m_WriteFds );
  321.  
  322.     timeval tv = { 0 /*sec*/, 1000 /*usec*/ };
  323.     int iRetCode = select( 0, NULL, &m_WriteFds, NULL, &tv );
  324.     if (iRetCode == SOCKET_ERROR)
  325.     {
  326.         // It could be that one of the descriptor sets contains an entry
  327.         // that is no longer a socket (e.g. when a socket is closed).
  328.         // This is okay.  It occurs when a connection is closed at the
  329.         // other end.
  330.         int iErr = WSAGetLastError();
  331.         if (iErr != WSAENOTSOCK)
  332.         {
  333.             ASSERT(FALSE);
  334.             return (FALSE);
  335.         }
  336.     }
  337.  
  338.     return (TRUE);
  339. }
  340.  
  341.  
  342.  
  343.  
  344. BOOL CCeSocket::SetForReadnWrite()
  345. {
  346.     FD_CLR( m_hSocket, &m_ReadFds );
  347.     FD_SET( m_hSocket, &m_ReadFds );
  348.     FD_CLR( m_hSocket, &m_WriteFds );
  349.     FD_SET( m_hSocket, &m_WriteFds );
  350.  
  351.     timeval tv = { 0 /*sec*/, 1000 /*usec*/ };
  352.     int iRetCode = select( 0, &m_ReadFds, &m_WriteFds, NULL, &tv );
  353.     if (iRetCode == SOCKET_ERROR)
  354.     {
  355.         // It could be that one of the descriptor sets contains an entry
  356.         // that is no longer a socket (e.g. when a socket is closed).
  357.         // This is okay.  It occurs when a connection is closed at the
  358.         // other end.
  359.         int iErr = WSAGetLastError();
  360.         if (iErr != WSAENOTSOCK)
  361.         {
  362.             ASSERT(FALSE);
  363.             return (FALSE);
  364.         }
  365.     }
  366.  
  367.     return (TRUE);
  368. }
  369.  
  370.  
  371.  
  372.  
  373. BOOL CCeSocket::DoAccept()
  374. {
  375.     // If not a valid socket, then pause and return.
  376.     if (! IsAlive())
  377.     {
  378.         Sleep( 100 );
  379.         return (FALSE);
  380.     }
  381.  
  382.     // Make sure that this *is* a listening socket.
  383.     if (! IsListening())
  384.     {
  385.         Sleep( 100 );
  386.         return (FALSE);
  387.     }
  388.  
  389.     // If this socket is not checked for readability, then return.
  390.     if (! FD_ISSET( m_hSocket, &m_ReadFds ))
  391.     {
  392.         Sleep( 100 );
  393.         // Reset for next connection.                                     
  394.         SetForRead();
  395.         return (FALSE);
  396.     }
  397.  
  398.     // Make sure that the handle is attached.
  399.     // NOTE: This should already have been done in CreateListeningSocket().
  400.     if (! LookupHandle( m_hSocket, FALSE ))      
  401.         Attach( m_hSocket );
  402.  
  403.     // Send an FD_ACCEPT message.
  404.     ::SendMessage( AfxGetCeSocketWindow(), WM_SOCKET_NOTIFY, 
  405.                    (WPARAM)m_hSocket, (LPARAM)FD_ACCEPT );
  406.     
  407.     // Delay before resetting.
  408.     Sleep( 100 );
  409.  
  410.     // Reset for next connection.
  411.     SetForRead();
  412.  
  413.     return (TRUE);
  414. }
  415.  
  416.  
  417.  
  418.  
  419. BOOL CCeSocket::DoConnect()
  420. {
  421.      // If not a valid socket, then pause and return.
  422.      if (! IsAlive())
  423.      {
  424.          Sleep( 100 );
  425.          return (FALSE);
  426.      }
  427.  
  428.      // Make sure that this is *not* a listening socket.
  429.      if (IsListening())
  430.      {
  431.          Sleep( 100 );
  432.          return (FALSE);
  433.      }
  434.  
  435.      // If this socket is not checked for writability, then return.
  436.      if (! FD_ISSET( m_hSocket, &m_WriteFds ))
  437.      {
  438.          Sleep( 100 );
  439.          // Reset for next connection.
  440.          SetForReadnWrite();
  441.         return (FALSE);  // TEMP
  442.     }
  443.  
  444.      // Set m_bIsConnected flag.
  445.      m_bIsConnected = TRUE;
  446.  
  447.      // Make sure that the handle is attached.
  448.      // NOTE: This should already have been done in CreateListeningSocket().
  449.      if (! LookupHandle( m_hSocket, FALSE ))
  450.          Attach( m_hSocket );
  451.  
  452.      // Send an FD_CONNECT message.
  453.     if(!m_bQuit)
  454.         ::PostMessage( AfxGetCeSocketWindow(), WM_SOCKET_NOTIFY,
  455.                     (WPARAM)m_hSocket, (LPARAM)FD_CONNECT );
  456.  
  457.      // Delay before resetting.
  458.      Sleep( 100 );
  459.  
  460.      return (TRUE);
  461. }
  462.  
  463.                                                                       
  464.  
  465.  
  466. BOOL CCeSocket::DoRead()
  467. {
  468.     // If *not* a valid socket, then pause and return.
  469.     if (! IsAlive())
  470.     {
  471.         Sleep( 100 );
  472.         return (FALSE);
  473.     }
  474.  
  475.     // Make sure that this is *not* a listening socket.
  476.     if (IsListening())
  477.     {
  478.         Sleep( 100 );
  479.         return (FALSE);
  480.     }
  481.  
  482.     // Check if the socket is tagged for readability. If not,
  483.     // then return now.
  484.     if (! FD_ISSET( m_hSocket, &m_ReadFds ))
  485.         return (FALSE);
  486.  
  487.      // Set m_bIsConnected flag.
  488.      m_bIsConnected = TRUE;
  489.  
  490.     // We have a readable socket.  Make sure that it is attached.
  491.     if (! LookupHandle( m_hSocket, FALSE ))
  492.         Attach( m_hSocket );
  493.  
  494.     // If there is data ready to be read, then send a WM_SOCKET_NOTIFY/FD_READ message.
  495.     if (IsReadReady())
  496.         ::SendMessage( AfxGetCeSocketWindow(), WM_SOCKET_NOTIFY,
  497.                        (WPARAM)m_hSocket, (LPARAM)FD_READ );
  498.  
  499.     return (FALSE);
  500. }
  501.  
  502.  
  503.  
  504.  
  505. BOOL CCeSocket::SetNonblocking()
  506. {
  507.     unsigned long ulResult = 1;  // nonzero => non-blocking
  508.  
  509.     if (ioctlsocket( m_hSocket, FIONBIO, &ulResult ) == SOCKET_ERROR)
  510.     {
  511.         int iErr = WSAGetLastError();
  512.         if (iErr != WSAENOTSOCK)
  513.             ASSERT(FALSE);
  514.         return (FALSE);
  515.     }
  516.  
  517.     return (TRUE);
  518. }
  519.  
  520.  
  521.  
  522.  
  523. BOOL CCeSocket::SetBlocking()
  524. {
  525.     unsigned long ulResult = 0;  // zero => blocking
  526.  
  527.     if (ioctlsocket( m_hSocket, FIONBIO, &ulResult ) == SOCKET_ERROR)
  528.     {
  529.         int iErr = WSAGetLastError();
  530.         if (iErr != WSAENOTSOCK)
  531.             ASSERT(FALSE);
  532.         return (FALSE);
  533.     }
  534.  
  535.     return (TRUE);
  536. }
  537.  
  538.  
  539.  
  540.  
  541. //  
  542. //  L I S T E N   &   D A T A   T H R E A D S
  543. //
  544.  
  545.  
  546.  
  547. //  
  548. unsigned int AFX_CDECL ListenThread( LPVOID pvParams )
  549. {
  550.     CCeSocket* pListenSocket = (CCeSocket*)pvParams;
  551.  
  552.     ASSERT(pListenSocket);
  553.  
  554.     // Keep checking the "listening" socket for an accept.
  555.     while (pListenSocket->m_pListenThread)
  556.     {
  557.         // Do [blocking] accept.
  558.         // May send an (WM_SOCKET_NOTIFY/FD_ACCEPT) window message.
  559.         if ((pListenSocket) && (pListenSocket->m_hSocket != INVALID_SOCKET))
  560.             pListenSocket->DoAccept();
  561.  
  562.         // Delay between iterations.
  563.         Sleep( 200 );
  564.     }
  565.  
  566.     return (0);
  567. }
  568.  
  569.  
  570.  
  571. //  
  572. unsigned int AFX_CDECL DataThread( void* pvParams )
  573. {
  574.     CPtrList*    pClientList = &CeDataSockets;
  575.     timeval      tv          = { 0 /*sec*/, 1000 /*usec*/ };
  576.  
  577.     while (1)
  578.     {        
  579.         // Check the "client" sockets for a read.
  580.         int iCount = pClientList->GetCount();
  581.         if (iCount < 1)
  582.         {
  583.             Sleep( 100);
  584.             continue;
  585.         }
  586.         for(POSITION pos = pClientList->GetHeadPosition(); pos != NULL;)
  587.         {
  588.             CCeSocket* pSocket = (CCeSocket*)pClientList->GetNext(pos);
  589.             ASSERT(pSocket);
  590.  
  591.             if(!pSocket->m_bConnectCalled)
  592.                 continue;
  593.  
  594.             if (pSocket->m_hSocket == INVALID_SOCKET)
  595.             {
  596.                 // NOTE: A DataSocket's m_hSocket gets filled-in by AsyncSocket::Accept(pSocket).
  597.                 //       If we reach this point then AsyncSocket::Accept(pSocket) has not yet
  598.                 //       been called.
  599.                 continue;
  600.             }
  601.  
  602.             // Set the socket to non-blocking.
  603.             if (!pSocket->SetNonblocking())
  604.                 continue;
  605.  
  606.             // May send an (WM_SOCKET_NOTIFY/FD_READ) window message.
  607.             BOOL bRetCode = pSocket->DoRead();
  608.             if (bRetCode)
  609.             {
  610.                 FD_CLR(pSocket->m_hSocket, &pSocket->m_ReadFds );
  611.                 FD_SET(pSocket->m_hSocket, &pSocket->m_ReadFds );
  612.             }
  613.              // May send an (WM_SOCKET_NOTIFY/FD_CONNECT) window message.
  614.             // NOTE: For use by data sockets on the client side.
  615.              if (!pSocket->m_bIsConnected)
  616.             {
  617.                 Sleep(100);
  618.                 if(!pSocket->m_bQuit)
  619.                      pSocket->DoConnect();
  620.             }
  621.         }
  622.  
  623.         // NOTE: Setting this too low breaks the app (e.g. 20 mSec).
  624.         Sleep( 200 );
  625.  
  626.         iCount = pClientList->GetCount();
  627.         if (iCount < 1)
  628.         {
  629.             Sleep( 100 );
  630.             continue;
  631.         }
  632.  
  633.         // Reset for next connection.
  634.         // NOTE: The Reset loop is separate from the Read loop because a
  635.         //       socket may get closed during the course of socket_DoRead().
  636.         //       Hence, we need to iterate through an updated pClientList.
  637.         for(pos = pClientList->GetHeadPosition(); pos != NULL;)
  638.         {
  639.             CCeSocket* pSocket = (CCeSocket*)pClientList->GetNext(pos);
  640.             if (pSocket->m_hSocket == INVALID_SOCKET)
  641.             {
  642.                 // NOTE: A DataSocket's m_hSocket gets filled-in by AsyncSocket::Accept(pSocket).
  643.                 //       If we reach this point then AsyncSocket::Accept(pSocket) has not yet
  644.                 //       been called.
  645.                 continue;
  646.             }
  647.             FD_CLR(pSocket->m_hSocket, &pSocket->m_ReadFds );
  648.             FD_SET(pSocket->m_hSocket, &pSocket->m_ReadFds );
  649.              FD_CLR(pSocket->m_hSocket, &pSocket->m_WriteFds );
  650.              if (! pSocket->m_bIsConnected)
  651.                  FD_SET(pSocket->m_hSocket, &pSocket->m_WriteFds );
  652.              int iRetCode = select( 0, &pSocket->m_ReadFds, &pSocket->m_WriteFds, NULL, &tv );
  653.             if (iRetCode == SOCKET_ERROR)
  654.             {
  655.                 int iErr = WSAGetLastError();
  656.                 if (iErr != WSAENOTSOCK)
  657.                     ASSERT(FALSE);
  658.             }
  659.         }
  660.     }
  661.  
  662.     return (0);
  663. }
  664. #endif // _WIN32_WCE_NO_WINSOCK
  665.  
  666. IMPLEMENT_DYNAMIC(CCeSocket, CSocket)
  667.